home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / system-config-printer / AdvancedServerSettings.py next >
Encoding:
Python Source  |  2009-05-05  |  14.5 KB  |  407 lines

  1. #!/usr/bin/env python
  2.  
  3. ## system-config-printer
  4.  
  5. ## Copyright (C) 2008, 2009 Red Hat, Inc.
  6. ## Copyright (C) 2008, 2009 Tim Waugh <twaugh@redhat.com>
  7.  
  8. ## This program is free software; you can redistribute it and/or modify
  9. ## it under the terms of the GNU General Public License as published by
  10. ## the Free Software Foundation; either version 2 of the License, or
  11. ## (at your option) any later version.
  12.  
  13. ## This program is distributed in the hope that it will be useful,
  14. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. ## GNU General Public License for more details.
  17.  
  18. ## You should have received a copy of the GNU General Public License
  19. ## along with this program; if not, write to the Free Software
  20. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. from gettext import gettext as _
  23. import gobject
  24. import gtk
  25. import os
  26. import tempfile
  27. import time
  28.  
  29. from errordialogs import *
  30.  
  31. class AdvancedServerSettingsDialog:
  32.     RESOURCE="/admin/conf/cupsd.conf"
  33.  
  34.     def __init__ (self, cupsconn, parent=None, on_apply=None):
  35.         self.cupsconn = cupsconn
  36.         self.on_apply = on_apply
  37.  
  38.         # Signal handler IDs.
  39.         self.handler_ids = {}
  40.  
  41.         dialog = gtk.Dialog (_("Advanced Server Settings"),
  42.                              parent,
  43.                              gtk.DIALOG_MODAL |
  44.                              gtk.DIALOG_DESTROY_WITH_PARENT,
  45.                              (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
  46.                               gtk.STOCK_OK, gtk.RESPONSE_OK))
  47.         dialog.set_default_response (gtk.RESPONSE_OK)
  48.         dialog.set_border_width (6)
  49.         dialog.set_resizable (False)
  50.         dialog.set_has_separator (False)
  51.         self.connect (dialog, 'response', self.on_response)
  52.         self.dialog = dialog
  53.  
  54.         frames_vbox = gtk.VBox (False, 6)
  55.         dialog.vbox.pack_start (frames_vbox, False, False, 0)
  56.  
  57.         history_frame = gtk.Frame ()
  58.         label = gtk.Label ('<b>' + _("Job History") + '</b>')
  59.         label.set_use_markup (True)
  60.         history_frame.set_label_widget (label)
  61.         history_frame.set_shadow_type (gtk.SHADOW_NONE)
  62.         frames_vbox.pack_start (history_frame, False, False, 0)
  63.  
  64.         align = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  65.         align.set_padding (0, 0, 12, 0)
  66.         history_frame.add (align)
  67.         vbox = gtk.VBox (False, 0)
  68.         align.add (vbox)
  69.         rb1 = gtk.RadioButton (None, _("Do not preserve job history"), False)
  70.         self.rbPreserveJobNone = rb1
  71.         rb2 = gtk.RadioButton (rb1, _("Preserve job history but not files"),
  72.                                False)
  73.         self.rbPreserveJobHistory = rb2
  74.         rb3 = gtk.RadioButton (rb1, _("Preserve job files (allow reprinting)"),
  75.                                False)
  76.         self.rbPreserveJobFiles = rb3
  77.         vbox.pack_start (rb1, False, False, 0)
  78.         vbox.pack_start (rb2, False, False, 0)
  79.         vbox.pack_start (rb3, False, False, 0)
  80.  
  81.         browse_frame = gtk.Frame ()
  82.         label = gtk.Label ('<b>' + _("Browse Servers") + '</b>')
  83.         label.set_use_markup (True)
  84.         browse_frame.set_label_widget (label)
  85.         browse_frame.set_shadow_type (gtk.SHADOW_NONE)
  86.         frames_vbox.pack_start (browse_frame, False, False, 0)
  87.  
  88.         align = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  89.         align.set_padding (0, 0, 12, 0)
  90.         browse_frame.add (align)
  91.         vbox = gtk.VBox (False, 6)
  92.         align.add (vbox)
  93.         label = gtk.Label (_("Usually print servers broadcast their "
  94.                              "queues.  Specify print servers below "
  95.                              "to periodically ask for queues instead."))
  96.         label.set_line_wrap (True)
  97.         vbox.pack_start (label, False, False, 0)
  98.         hbox = gtk.HBox (False, 6)
  99.         vbox.pack_start (hbox, False, False, 0)
  100.  
  101.         scrollwin = gtk.ScrolledWindow ()
  102.         scrollwin.set_shadow_type (gtk.SHADOW_IN)
  103.         scrollwin.set_policy (gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  104.         hbox.pack_start (scrollwin, True, True, 0)
  105.         treeview = gtk.TreeView ()
  106.         treeview.set_headers_visible (False)
  107.         scrollwin.add (treeview)
  108.         selection = treeview.get_selection ()
  109.         selection.set_mode (gtk.SELECTION_MULTIPLE)
  110.         self.connect (selection, 'changed', self.on_treeview_selection_changed)
  111.         col = gtk.TreeViewColumn ('', gtk.CellRendererText (), text=0)
  112.         treeview.append_column (col)
  113.         self.browse_treeview = treeview
  114.  
  115.         bb = gtk.VButtonBox ()
  116.         bb.set_layout (gtk.BUTTONBOX_START)
  117.         hbox.pack_start (bb, False, False, 0)
  118.  
  119.         add = gtk.Button (stock=gtk.STOCK_ADD)
  120.         bb.add (add)
  121.         self.connect (add, 'clicked', self.on_add_clicked)
  122.         self.add = add
  123.         remove = gtk.Button (stock=gtk.STOCK_REMOVE)
  124.         remove.set_sensitive (False)
  125.         bb.add (remove)
  126.         self.connect (remove, 'clicked', self.on_remove_clicked)
  127.         self.remove = remove
  128.  
  129.         # Fetch cupsd.conf
  130.         f = tempfile.TemporaryFile ()
  131.         try:
  132.             cupsconn.getFile (self.RESOURCE, file=f)
  133.         except cups.HTTPError, s:
  134.             show_HTTP_Error (s, dialog)
  135.             raise
  136.  
  137.         def parse_yesno (line):
  138.             arg1 = line.split (' ')[1].strip ()
  139.             if arg1 in ['true', 'on', 'enabled', 'yes']:
  140.                 return True
  141.             if arg1 in ['false', 'off', 'disabled', 'no', '0']:
  142.                 return False
  143.             try:
  144.                 if int (arg1) != 0:
  145.                     return True
  146.             except:
  147.                 pass
  148.             raise RuntimeError
  149.  
  150.         preserve_job_history = True
  151.         preserve_job_files = False
  152.         browsing = True
  153.         self.browse_poll = []
  154.         f.seek (0)
  155.         for line in f.readlines ():
  156.             l = line.lower ()
  157.             if l.startswith ("preservejobhistory "):
  158.                 try:
  159.                     preserve_job_history = parse_yesno (l)
  160.                 except:
  161.                     pass
  162.             elif l.startswith ("preservejobfiles "):
  163.                 try:
  164.                     preserve_job_files = parse_yesno (l)
  165.                 except:
  166.                     pass
  167.             elif l.startswith ("browsing "):
  168.                 try:
  169.                     browsing = parse_yesno (l)
  170.                 except:
  171.                     pass
  172.             elif l.startswith ("browsepoll "):
  173.                 self.browse_poll.append (line[len ("browsepoll "):].strip ())
  174.  
  175.         if not browsing:
  176.             browse_frame.set_sensitive (False)
  177.             
  178.         if preserve_job_files:
  179.             self.rbPreserveJobFiles.set_active (True)
  180.         elif preserve_job_history:
  181.             self.rbPreserveJobHistory.set_active (True)
  182.         else:
  183.             self.rbPreserveJobNone.set_active (True)
  184.  
  185.         self.preserve_job_history = preserve_job_history
  186.         self.preserve_job_files = preserve_job_files
  187.  
  188.         model = gtk.ListStore (gobject.TYPE_STRING)
  189.         treeview.set_model (model)
  190.         for server in self.browse_poll:
  191.             model.append (row=[server])
  192.  
  193.         dialog.show_all ()
  194.  
  195.     def connect (self, widget, signal, handler, reason=None):
  196.         id = widget.connect (signal, handler)
  197.         if not self.handler_ids.has_key (reason):
  198.             self.handler_ids[reason] = []
  199.         self.handler_ids[reason].append ((widget, id))
  200.  
  201.     def disconnect (self, reason=None):
  202.         for (widget, id) in self.handler_ids[reason]:
  203.             widget.disconnect (id)
  204.         del self.handler_ids[reason]
  205.  
  206.     def __del__ (self):
  207.         self.dialog.destroy ()
  208.  
  209.     def on_treeview_selection_changed (self, selection):
  210.         self.remove.set_sensitive (selection.count_selected_rows () != 0)
  211.  
  212.     def on_add_clicked (self, button):
  213.         model = self.browse_treeview.get_model ()
  214.         iter = model.insert (0, row=[_("Enter IP address")])
  215.         button.set_sensitive (False)
  216.         col = self.browse_treeview.get_columns ()[0]
  217.         cell = col.get_cell_renderers ()[0]
  218.         cell.set_property ('editable', True)
  219.         self.browse_treeview.set_cursor ((0,), col, start_editing=True)
  220.         self.connect (cell, 'edited', self.on_browse_poll_edited,
  221.                       'edit')
  222.         self.connect (cell, 'editing-canceled', self.on_browse_poll_edit_cancel,
  223.                       'edit')
  224.  
  225.     def on_browse_poll_edited (self, cell, path, newvalue):
  226.         model = self.browse_treeview.get_model ()
  227.         iter = model.get_iter (path)
  228.         model.set_value (iter, 0, newvalue)
  229.         cell.stop_editing (canceled=False)
  230.         cell.set_property ('editable', False)
  231.         self.add.set_sensitive (True)
  232.         self.disconnect ('edit')
  233.         valid = True
  234.         if newvalue.find (' ') != -1:
  235.             valid = False
  236.         else:
  237.             count = 0
  238.             i = model.get_iter_first ()
  239.             while i:
  240.                 if model.get_value (i, 0) == newvalue:
  241.                     count += 1
  242.                     if count == 2:
  243.                         valid = False
  244.                         selection = self.browse_treeview.get_selection ()
  245.                         selection.select_iter (i)
  246.                         break
  247.                 i = model.iter_next (i)
  248.  
  249.         if not valid:
  250.             model.remove (iter)
  251.  
  252.     def on_browse_poll_edit_cancel (self, cell):
  253.         cell.stop_editing (canceled=True)
  254.         cell.set_property ('editable', False)
  255.         model = self.browse_treeview.get_model ()
  256.         iter = model.get_iter ((0,))
  257.         model.remove (iter)
  258.         self.add.set_sensitive (True)
  259.         self.remove.set_sensitive (False)
  260.         self.disconnect ('edit')
  261.  
  262.     def on_remove_clicked (self, button):
  263.         model = self.browse_treeview.get_model ()
  264.         selection = self.browse_treeview.get_selection ()
  265.         rows = selection.get_selected_rows ()
  266.         refs = map (lambda path: gtk.TreeRowReference (model, path),
  267.                     rows[1])
  268.         for ref in refs:
  269.             path = ref.get_path ()
  270.             iter = model.get_iter (path)
  271.             model.remove (iter)
  272.  
  273.     def on_response (self, dialog, response):
  274.         if (response == gtk.RESPONSE_CANCEL or
  275.             response != gtk.RESPONSE_OK):
  276.             self.disconnect ()
  277.             del self
  278.             return
  279.  
  280.         # See if there are changes.
  281.         preserve_job_files = self.rbPreserveJobFiles.get_active ()
  282.         preserve_job_history = (preserve_job_files or
  283.                                 self.rbPreserveJobHistory.get_active ())
  284.         model = self.browse_treeview.get_model ()
  285.         browse_poll = []
  286.         iter = model.get_iter_first ()
  287.         while iter:
  288.             browse_poll.append (model.get_value (iter, 0))
  289.             iter = model.iter_next (iter)
  290.  
  291.         if (set (browse_poll) == set (self.browse_poll) and
  292.             preserve_job_files == self.preserve_job_files and
  293.             preserve_job_history == self.preserve_job_history):
  294.             self.disconnect ()
  295.             del self
  296.             return
  297.  
  298.         # Fetch cupsd.conf afresh
  299.         f = tempfile.TemporaryFile ()
  300.         try:
  301.             self.cupsconn.getFile (self.RESOURCE, file=f)
  302.         except cups.HTTPError, s:
  303.             show_HTTP_Error (s, dialog)
  304.             return
  305.  
  306.         job_history_line = job_files_line = browsepoll_lines = ""
  307.  
  308.         # Default is to preserve job history
  309.         if not preserve_job_history:
  310.             job_history_line = "PreserveJobHistory No\n"
  311.  
  312.         # Default is not to preserve job files.
  313.         if preserve_job_files:
  314.             job_files_line = "PreserveJobFiles Yes\n"
  315.  
  316.         for server in browse_poll:
  317.             browsepoll_lines += "BrowsePoll %s\n" % server
  318.  
  319.         f.seek (0)
  320.         conf = tempfile.TemporaryFile ()
  321.         wrote_preserve_history = wrote_preserve_files = False
  322.         wrote_browsepoll = False
  323.         has_browsepoll = False
  324.         lines = f.readlines ()
  325.         for line in lines:
  326.             l = line.lower ().strip ()
  327.             if l.startswith ("browsepoll "):
  328.                 has_browsepoll = True
  329.                 break
  330.  
  331.         for line in lines:
  332.             l = line.lower ().strip ()
  333.             if l.startswith ("preservejobhistory "):
  334.                 if wrote_preserve_history:
  335.                     # Don't write out another line with this keyword.
  336.                     continue
  337.                 # Alter this line before writing it out.
  338.                 line = job_history_line
  339.                 wrote_preserve_history = True
  340.             elif l.startswith ("preservejobfiles "):
  341.                 if wrote_preserve_files:
  342.                     # Don't write out another line with this keyword.
  343.                     continue
  344.                 # Alter this line before writing it out.
  345.                 line = job_files_line
  346.                 wrote_preserve_files = True
  347.             elif (has_browsepoll and
  348.                   l.startswith ("browsepoll ")):
  349.                 if wrote_browsepoll:
  350.                     # Ignore extra BrowsePoll lines.
  351.                     continue
  352.                 # Write new BrowsePoll section.
  353.                 conf.write (browsepoll_lines)
  354.                 wrote_browsepoll = True
  355.                 # Don't write out the original BrowsePoll line.
  356.                 continue
  357.             elif (not has_browsepoll and
  358.                   l.startswith ("browsing ")):
  359.                 if not wrote_browsepoll:
  360.                     # Write original Browsing line.
  361.                     conf.write (line)
  362.                     # Write new BrowsePoll section.
  363.                     conf.write (browsepoll_lines)
  364.                     wrote_browsepoll = True
  365.                     continue
  366.  
  367.             conf.write (line)
  368.  
  369.         if not wrote_preserve_history:
  370.             conf.write (job_history_line)
  371.         if not wrote_preserve_files:
  372.             conf.write (job_files_line)
  373.         if not wrote_browsepoll:
  374.             conf.write (browsepoll_lines)
  375.  
  376.         conf.flush ()
  377.         fd = conf.fileno ()
  378.         os.lseek (fd, 0, os.SEEK_SET)
  379.         try:
  380.             self.cupsconn.putFile ("/admin/conf/cupsd.conf", fd=fd)
  381.         except cups.HTTPError, s:
  382.             show_HTTP_Error (s, dialog)
  383.             return
  384.  
  385.         # Give the server a chance to process our request.
  386.         time.sleep (1)
  387.  
  388.         # Now reconnect, in case the server needed to reload.
  389.         try:
  390.             attempt = 1
  391.             while attempt <= 5:
  392.                 try:
  393.                     self.cupsconn._connect ()
  394.                     break
  395.                 except RuntimeError:
  396.                     # Connection failed.
  397.                     time.sleep (1)
  398.                     attempt += 1
  399.         except AttributeError:
  400.             # _connect method is part of the authconn.Connection
  401.             # interface, so don't fail if that method doesn't exist.
  402.             pass
  403.  
  404.         self.disconnect ()
  405.         self.on_apply ()
  406.         del self
  407.